package com.dingwen.treasure.business.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.dingwen.treasure.base.constant.PayConstant;
import com.dingwen.treasure.business.model.dto.PayDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * pay 抽象模板: 函数时接口实现
 *
 * @author dingwen
 * @date 2022/04/26
 */
@Component
@Slf4j
public abstract class AbstractPayServiceImplementsForFunction {


    /**
     * 执行
     */
    public void execute(PayDto payDTO) {

        // 1. 策略适配
        payDTO = strategy(payDTO);


        // 2. 执行请求
        String resultStr;
        try {
            resultStr = payDTO.getSupplierRequest().get();
        } catch (Exception e) {
            log.error("执行请求出现异常，错误信息：{}", e.getMessage());
            return;
        }

        if (StrUtil.isBlank(resultStr) || !JSONUtil.isTypeJSON(resultStr)) {
            log.info("执行请求，返回结果为空或不是Json，返回内容：{}", resultStr);
            return;
        }

        // 3. 返回结果解析
        JSONObject resultJsonObject = JSONUtil.parseObj(resultStr);

        String code = String.valueOf(resultJsonObject.get(payDTO.getResultCodeKey()));

        if (payDTO.getPredicateResult().test(code)) {
            // 4. 成功
            payDTO.getConsumerSuccess().accept(resultJsonObject);
            log.info("执行成功");
            // 5. 原始数据存库
            payDTO.getConsumerRawData().accept(resultJsonObject);
        } else {
            // 6. 失败
            payDTO.getConsumerFail().accept(resultJsonObject);
            log.info("执行失败");
        }
    }


    /**
     * 策略
     *
     * @param payDTO 支付模板dto
     * @return {@link PayDto}
     */
    protected PayDto strategy(PayDto payDTO) {

        // 执行请求
        payDTO.setSupplierRequest(getInvokeRequestMethod());


        // 结果返回码KEY
        if (StrUtil.isBlank(payDTO.getResultCodeKey())) {
            payDTO.setResultCodeKey(PayConstant.DEFAULT_RESULT_CODE_KEY);
        }

        // 返回结果决策
        if (ObjectUtil.isEmpty(payDTO.getPredicateResult())) {
            payDTO.setPredicateResult(getDefaultPredicateResult());
        }

        // 失败消费
        if (ObjectUtil.isEmpty(payDTO.getConsumerFail())) {
            payDTO.setConsumerFail(getDefaultConsumerFail());
        }


        // 成功消费

        if (ObjectUtil.isEmpty(payDTO.getConsumerSuccess())) {
            payDTO.setConsumerSuccess(getDefaultConsumerSuccess());
        }

        // 原始数据存库
        if (ObjectUtil.isEmpty(payDTO.getConsumerRawData())) {
            payDTO.setConsumerRawData(getDefaultConsumerRawData());
        }

        return payDTO;

    }

    /**
     * 接口返回code判断
     *
     * @return {@link Predicate}<{@link String}>
     */
    private Predicate<String> getDefaultPredicateResult() {
        return PayConstant.DEFAULT_RESULT_CODE_VALUE::equals;
    }

    /**
     * 获取默认消费者失败
     *
     * @return {@link Consumer}<{@link JSONObject}>
     */
    private Consumer<JSONObject> getDefaultConsumerFail() {
        return jsonObject -> log.info("consumer fail executor ...,结构:{}", JSONUtil.toJsonPrettyStr(jsonObject));
    }

    /**
     * 获得默认消费者成功
     *
     * @return {@link Consumer}<{@link JSONObject}>
     */
    private Consumer<JSONObject> getDefaultConsumerSuccess() {
        return jsonObject -> log.info("consumer success executor ...,结构: \n{}", JSONUtil.toJsonPrettyStr(jsonObject));
    }

    private Consumer<JSONObject> getDefaultConsumerRawData() {
        return jsonObject -> log.info("consumer raw data  executor ...,结构：\n{}", JSONUtil.toJsonPrettyStr(jsonObject));
    }

    /**
     * 获取调用请求方法
     *
     * @return {@link Supplier}<{@link String}>
     */
    protected abstract Supplier<String> getInvokeRequestMethod();
}
